﻿using CubeCube.Tile;
using CubeCube.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CubeCube.World.Generator
{
    //粒子堆生成器
    public class ParticleDepositionWorldGenerator : CubeWorldGenerator
    {
        private Random generator = new Random();

        private byte tileType;
        private WorldSizeRelativeValue minParticlesRV;
        private WorldSizeRelativeValue maxParticlesRV;
        private WorldSizeRelativeValue minDropsRV;
        private WorldSizeRelativeValue maxDropsRV;

        private int sidesToCheck = 9;
        private int[][] nearPositions;

        public ParticleDepositionWorldGenerator(
            WorldSizeRelativeValue minParticlesRV,
            WorldSizeRelativeValue maxParticlesRV,
            WorldSizeRelativeValue minDropsRV,
            WorldSizeRelativeValue maxDropsRV,
            byte tileType)
        {
            this.minParticlesRV = minParticlesRV;
            this.maxParticlesRV = maxParticlesRV;
            this.minDropsRV = minDropsRV;
            this.maxDropsRV = maxDropsRV;
            this.tileType = tileType;

            nearPositions = new int[3][];
            nearPositions[0] = new int[3];
            nearPositions[1] = new int[3];
            nearPositions[2] = new int[3];
        }

        public override bool Generate(Chunk.Chunk chunk)
        {
            //堆的个数
            int drops = generator.Next(minDropsRV.EvaluateInt(chunk), maxDropsRV.EvaluateInt(chunk));

            TileManager tileManager = chunk.tileManager;

            for (int i = 0; i < drops; i++)
            {
                int localX = generator.Next(2, tileManager.sizeX - 2);
                int localZ = generator.Next(2, tileManager.sizeZ - 2);
                sidesToCheck = generator.Next(3, 10);

                //每个堆的粒子个数,决定了堆有多大
                int particles = generator.Next(minParticlesRV.EvaluateInt(chunk), maxParticlesRV.EvaluateInt(chunk));

                for (int j = 0; j < particles; j++)
                    DropParticle(localX, localZ, chunk);
            }

            return true;
        }

        private void DropParticle(int localX, int localZ, Chunk.Chunk chunk)
        {
            int worldX = localX + chunk.tileOffset.x;
            int worldZ = localZ + chunk.tileOffset.z;

            TileManager tileManager = chunk.tileManager;

            bool particleDropped = false;

            while (localX > 0 && localZ > 0 && localX < tileManager.sizeX - 1 && localZ < tileManager.sizeZ - 1 && particleDropped == false)
            {
                int middleY = 0;

                for (int ax = -1; ax <= 1; ax++)
                {
                    for (int az = -1; az <= 1; az++)
                    {
                        int worldTopY = tileManager.GetTopPosition(worldX + ax, worldZ + az);
                        if (tileManager.GetTileType(new IndexPosition(worldX + ax, worldTopY, worldZ + az)) != TileDefinition.EMPTY_TILE_TYPE)
                            worldTopY++;

                        nearPositions[ax + 1][az + 1] = worldTopY;

                        if (ax == 0 && az == 0)
                            middleY = worldTopY;
                    }
                }

                int finalY = middleY;
                int finalX = worldX;
                int finalZ = worldZ;

                int from = generator.Next(9);
                bool finalPosition = true;

                for (int j = 0; j < sidesToCheck; j++)
                {
                    int ax = (((j + from) % 9) % 3) - 1;
                    int az = (((j + from) % 9) / 3) - 1;

                    int worldY = nearPositions[ax + 1][az + 1];
                    if (worldY < finalY)
                    {
                        finalX = worldX + ax;
                        finalZ = worldX + az;
                        finalY = worldY;
                        finalPosition = false;
                        break;
                    }
                }

                if (finalY >= tileManager.sizeY + chunk.tileOffset.y)
                    break;

                if (finalPosition)
                {
                    tileManager.SetTileType(new IndexPosition(finalX, finalY, finalZ), tileType);
                    particleDropped = true;
                }
                else
                {
                    worldX = finalX;
                    worldZ = finalZ;
                }
            }

            if (particleDropped == false && tileManager.IsValidTile(new IndexPosition(worldX, 0, worldZ)))
            {
                int worldY = tileManager.GetTopPosition(worldX, worldZ);

                IndexPosition worldPos = new IndexPosition(worldX, worldY, worldZ);

                if (tileManager.GetTileType(worldPos) != TileDefinition.EMPTY_TILE_TYPE)
                    worldPos.y++;
                if (worldY < tileManager.sizeY)
                    tileManager.SetTileType(worldPos, tileType);
            }
        }

        public override string ToString()
        {
            return "Creating mountains";
        }
    }
}
